from collections import namedtuple
import os
from Tkinter import PhotoImage
from sys import maxint
from ctypes import c_ulong

# Globals

LIGHT_SQUARES = 'tan'
DARK_SQUARES = 'dark green'
OUTLINE_COLOR = 'white'
LIGHT_CHECKERS = 'white'
DARK_CHECKERS = 'red'
DEFAULT_SIZE = 400
BOARD_SIZE = 8
CHECKER_SIZE = 30
MAX_VALID_SQ = 32
OUTLINE_COLOR = 'white'
FREE = 16
PWHITE = 1
PBLACK = 2
KWHITE = 4
KBLACK = 8
RESOURCES = os.path.join(os.getcwd(), 'resources')
DIRECTIONS = namedtuple('Directions', ['SW', 'NW', 'SE', 'NE'])
MASK32 = c_ulong(0xffffffff)
DEFAULT_SEARCH_DEPTH = 6
DEFAULT_ALGORITHM = 'alpha-beta'
DEFAULT_HEURISTIC = 1

ALGORITHM_LABEL = 'Algorithm'
SEARCH_DEPTH_LABEL = 'Depth'
HEURISTIC_FUNCTION_LABEL = 'Heuristic'
INFO_TEMPLATE = 'Current turn: %s'

g_pdict = {}
def init_starting_checkers_dict():
    for index in xrange(32):
        if 0 <= index < 12:
            g_pdict[index] = PWHITE
        elif 12 <= index < 20:
            g_pdict[index] = FREE
        else:
            g_pdict[index] = PBLACK
            
g_precomputed_16bits = {0:0}
def init_precomputed_16bits():
    for index in xrange(2**16):
        g_precomputed_16bits[index] = (index & 1) + g_precomputed_16bits[index / 2]

g_precomputed_masks = {0:0}
def init_precomputed_masks():
    for index in xrange(33):
        g_precomputed_masks[index] = (2 ** index) - 1
        
g_precomputed_aligned32 = {0:0}
def init_precomputed_aligned32():
    for index in xrange(33):
        g_precomputed_aligned32[index] = (2 ** index) - 1
        g_precomputed_aligned32[index] = g_precomputed_aligned32[index] << (32 - index)

def create_grid_map():
    """ Maps internal board indices to grid (row, col) coordinates """
    # (row, col): (0,0) to (7,7) 
    grd = {}
    grd[0] = (7,0); grd[1] = (7,2); grd[2] = (7,4); grd[3] = (7,6);
    grd[4] = (6,1); grd[5] = (6,3); grd[6] = (6,5); grd[7] = (6,7);
    grd[8] = (5,0); grd[9] = (5,2); grd[10] = (5,4); grd[11] = (5,6);
    grd[12] = (4,1); grd[13] = (4,3); grd[14] = (4,5); grd[15] = (4,7);
    grd[16] = (3,0); grd[17] = (3,2); grd[18] = (3,4); grd[19] = (3,6);
    grd[20] = (2,1); grd[21] = (2,3); grd[22] = (2,5); grd[23] = (2,7);
    grd[24] = (1,0); grd[25] = (1,2); grd[26] = (1,4); grd[27] = (1,6);
    grd[28] = (0,1); grd[29] = (0,3); grd[30] = (0,5); grd[31] = (0,7);
    return grd

def create_position_map():
    """ Maps compressed grid indices xi + yi * 8 to internal
        board indices """
    pos = {}
    pos[1] = 28;   pos[3]  = 29; pos[5] =  30; pos[7]  = 31
    pos[8] = 24;   pos[10] = 25; pos[12] = 26; pos[14] = 27
    pos[17] = 20;  pos[19] = 21; pos[21] = 22; pos[23] = 23
    pos[24] = 16;  pos[26] = 17; pos[28] = 18; pos[30] = 19
    pos[33] = 12;  pos[35] = 13; pos[37] = 14; pos[39] = 15
    pos[40] = 8;  pos[42] = 9; pos[44] = 10; pos[46] = 11
    pos[49] = 4;  pos[51] = 5; pos[53] = 6; pos[55] = 7
    pos[56] = 0;   pos[58] = 1;  pos[60] =  2; pos[62] = 3
    return pos

class CheckersGlobals:
    AVAILABLE_SQUARES = 32

class CheckersEnd:
    WHITE_WON = 0x0e1
    BLACK_WON = 0x0e2
    DRAW = 0x0e3
    
    @staticmethod
    def to_string(game_end):
        if game_end == CheckersEnd.WHITE_WON:
            return 'White won!'
        elif game_end == CheckersEnd.BLACK_WON:
            return 'Black won!'
        elif game_end == CheckersEnd.DRAW:
            return 'Draw!'
        else:
            raise ValueError('Unknown game end state')
  
class CheckersGameMode:
    HUMAN_VERSUS_AI = 0x0e1
    AI_VERSUS_AI = 0x0e2
    VERSUS_EXTERNAL_PROGRAM = 0x0e3
    
class CheckersTurns:
    BLACK = 0x0d1
    WHITE = 0x0d2
    
    @staticmethod
    def to_string(turn):
        if turn == CheckersTurns.WHITE:
            return 'White'
        elif turn == CheckersTurns.BLACK:
            return 'Black'
        else:
            str = 'Unrecognized turn %s' % (turn, )
            raise ValueError(str)
  

